今日內容:繼承(inheritance)、super、override、toString()、抽象(abstraction)、介面(interface)
過去在C++中是使用 ":" 進行繼承
public class Dog : public Animal{
// ...
}
而Java使用的是 extends 這個關鍵字
// 首先宣告Animal這個parent class (base class)
public class Animal{
boolean isAlive;
Animal(){
isAlive = true;
}
void eat(){
System.out.println("The animal is eating");
}
}
// 接著宣告Dog去extends Animal,Dog是subclass (derived class)
public class Dog extends Animal{
void speak(){
System.out.println("The dog goes *woof*");
}
}
// Cat也是一樣的道理
public class Cat extends Animal{
void speak(){
System.out.println("The cat goes *meow*")
}
}
這樣宣告出來的Dog或Cat函式都屬於Animal的subclass
而這麼做的目的就是為了之後的polymorphism,或者是方便進行管理、理解
super這個關鍵字用於subclass的constructor中
需要用super將資料傳回給parent class,才能正常宣告
public class Person{
String first;
String last;
Person(String first, String last){
this.first = first;
this.last = last;
}
void showName(){
System.out.printf("%s %s\n", this.first, this.last);
}
}
public class Student extends Person{
double gpa;
Student(String first, String last, double gpa){
super(first, last); // 系統會根據繼承的parent class自動去找資料,建構回去
this.gpa = gpa;
}
}
對於subclass可以讓他對同一個名稱的函式執行與parent class不一樣的操作
public class Animal{
void move(){
System.out.println("The animal is moving");
}
}
public class Fish extends Animal{
// 由於魚是swim不是run
@Override // 這邊加上 @Override 關鍵字,用意是提高程式可讀性,且compiler也可以幫忙進行檢查
void move(){
System.out.println("The anime is swimming");
}
}
Java的class都會有一個成員函式叫做toString(),而他是可以被override的
正常來說,我們println()一個物件,他會回傳這個物件的hash值
由於還沒開始學習資料結構,我還不了解hash和hash table實際上是在做甚麼,先暫時知道怎麼用就好
我們可以在自己宣告的class裡面對toString() override,就可以讓他輸出有意義的值(可以自己設定想看到的內容)
public class Car{
String make, model;
int year;
// ...
@Override
public String toString(){
return this.year + " " + this.make + " " + this.model;
// 回傳的型態是String,這邊使用 + 將資料組合成一個String,然後回傳
}
}
// 這樣當我們println(car),就會顯示對應的年份車種了
在class前面加關鍵字abstract,可以讓整個class變成抽象類別(不能被宣告出物件)
在method前面加abstract,也可以讓那個東西變成必須被subclass定義的內容
public abstract class Shape{
abstract double area(); // abstract method不須給予實作定義(implementation)
void display(){System.out.println("This is a shape");} // abstract class裡面也可以有非abstract的內容
}
// 使用extends進行繼承
public class Circle extends Shape{
double radius;
Circle(double radius){
this.radius = radius;
}
// 需要override area這個函式(所有abstract methods)才可以使這個class變得concrete,才能宣告出物件
@Override
double area(){return Math.PI * radius * radius}
}
public class Triangle extends Shape{
double base, height;
Triangle(double base, double height){
this.base = base;
this.height = height;
}
@Override
double area(){return 0.5 * base * height;}
}
public class Rectangle extends Shape{
double length, width;
Rectangle(double length, double width){
this.length = length;
this.width = width;
}
@Override
double area(){return length * width;}
}
接著在main函式中宣告
public class Main{
public static void main(String[] args){
Circle cirlce = new Circle(3);
Triangle triangle = new Triangle(4, 5);
Rectangle rectangle = new Rectangle(6, 7);
circle.display(); // 會顯示"This is a shape",是因為我們沒有在class中再override這個函式
System.out.println(circle.area());
System.out.println(triangle.area());
System.out.println(rectangle.area());
}
}
而Interface就是pure abstract class,也就是完全抽象類別,無法用於建構出物件
在繼承interface的時候不再像繼承class那樣使用extends關鍵字,而是需要用 implements 這個關鍵字
interface中只需要宣告method的回傳值與名稱,且不需要再加abstract(因為interface已經定義了他就是abstract的)
對於一個class,可以同時繼承多個interface,且必須要 @Override 每一個interface裡面的method才能使用,否則compiler會報錯
首先定義一個名為Animal的parent class
public class Animal{
String name;
int age;
Animal(String name, int age){
this.name = name;
this.age = age;
}
void eat(){
System.out.println(this.name + " is eating");
}
}
接著宣告兩個interface
public interface Flyable{
void fly();
}
public interface Swimmalbe{
vodi swim();
}
然後我們創建一個名為Duck的class,他屬於Animal,且同時會飛、會游泳
public class Duck extends Animal implements Flyable, Swimmable{
Duck(String name, int age){
super(name, age); // 用今天學到的super將資料傳回給parent class
}
// override interface的methods
@Override
void fly(){
System.out.println(this.name + " is flying in the sky");
}
@Override
void swim(){
System.out.println(this.name + " is swimming in the water");
}
// 加上屬於Duck自己的函式
void quack(){
System.out.println(this.name + " says Quack!");
}
}
最後在main函式中宣告Duck物件
public class Main{
public static void main(String[] args){
Duck donald = new Duck("Donald", 2);
System.out.println("Name: " + donald.name);
// Name: Donald
System.out.println("Age: " + donald.age);
// Age: 2
donald.eat();
// Donald is eating
donald.fly();
// Donald is flying in the sky
donald.swim();
// Donald is swimming in the water
donald.quack();
// Donald says Quack!
}
}
今天是接觸Java OOP的第二天,開始遇到一些理解上的問題了,以下是今天的提問與自我解答
為什麼要分class和interface?
一個class只能extends一個class,卻可以implements多個interface
class用於解決is-a relationship的問題(是一種...),而implements用於解決has-a capability的問題(有...能力)
分成這兩種可以在保證繼承的便利性的同時解決只能繼承一個class的問題
那extends和implements在概念上又有什麼實質上的差距?
extends是用於繼承,class繼承class,在保有parent class的意義的同時又可以額外增加自己的內容
而implements是用於實現,class實現interface,讓一個class可以同時實現多個interface的內容,解決單一繼承的問題
雖然用起來感覺只是對不同的名詞有不同的寫法,但實際上這是由於繼承的內容與目的的不同所導致的不同寫法
今天又是快樂學習的一天,明天繼續!